<script setup name="Simple" lang="ts">
import * as THREE from 'three';
import { MapControls } from 'three/examples/jsm/controls/MapControls.js';
import { gsap } from "gsap";
import * as dat from 'dat.gui';
import { ref, reactive, onMounted, onUnmounted, watch, computed } from 'vue';
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import Stone from '@/assets/texture/stone.jpg'
// import Worker from '@/assets/model/worker.glb?url'
import Worker from "@/assets/texture/worker.png";
import CheckLineTexture from '@/assets/texture/line.jpg'
// import Cad from '@/assets/model/blr1.json'
// import Edge from '@/assets/model/edge1.json'
import Cad from '@/assets/model/jz.json'
// import Edge from '@/assets/model/edge2.json'
import PointPic1 from '@/assets/texture/point-1.png'
import PointPic2 from '@/assets/texture/point-2.png'
import PointPic3 from '@/assets/texture/point-3.png'
import PointPic4 from '@/assets/texture/point-4.png'
import ZhDb0 from '@/assets/texture/zh-db-0.png'
import ZhDb1 from '@/assets/texture/zh-db-1.png'
import ZhDb2 from '@/assets/texture/zh-db-2.png'
import ZhDb3 from '@/assets/texture/zh-db-3.png'
import ZhFc0 from '@/assets/texture/zh-fc-0.png'
import ZhFc1 from '@/assets/texture/zh-fc-1.png'
import ZhFc2 from '@/assets/texture/zh-fc-2.png'
import ZhFc3 from '@/assets/texture/zh-fc-3.png'
import ZhFmh0 from '@/assets/texture/zh-fmh-0.png'
import ZhFmh1 from '@/assets/texture/zh-fmh-1.png'
import ZhFmh2 from '@/assets/texture/zh-fmh-2.png'
import ZhFmh3 from '@/assets/texture/zh-fmh-3.png'
import ZhKy0 from '@/assets/texture/zh-ky-0.png'
import ZhKy1 from '@/assets/texture/zh-ky-1.png'
import ZhKy2 from '@/assets/texture/zh-ky-2.png'
import ZhKy3 from '@/assets/texture/zh-ky-3.png'
import ZhSh0 from '@/assets/texture/zh-sh-0.png'
import ZhSh1 from '@/assets/texture/zh-sh-1.png'
import ZhSh2 from '@/assets/texture/zh-sh-2.png'
import ZhSh3 from '@/assets/texture/zh-sh-3.png'
import ZhWs0 from '@/assets/texture/zh-ws-0.png'
import ZhWs1 from '@/assets/texture/zh-ws-1.png'
import ZhWs2 from '@/assets/texture/zh-ws-2.png'
import ZhWs3 from '@/assets/texture/zh-ws-3.png'
import ZhZx0 from '@/assets/texture/zh-zx-0.png'
import ZhZx1 from '@/assets/texture/zh-zx-1.png'
import ZhZx2 from '@/assets/texture/zh-zx-2.png'
import ZhZx3 from '@/assets/texture/zh-zx-3.png'
import ZhTf0 from '@/assets/texture/zh-tf-0.png'
import ZhTf1 from '@/assets/texture/zh-tf-1.png'
import ZhTf2 from '@/assets/texture/zh-tf-2.png'
import ZhTf3 from '@/assets/texture/zh-tf-3.png'
import mapInfo from "@/utils/map-info.js"

interface PointInfoParam {
  name: string,
  posX: number,
  posY: number,
  posZ: number,
  inspecType?: any, // 图标类型
  inspecStatus: number,
}

let scene: any, camera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer
function initScene() {
  // 创建场景
  scene = new THREE.Scene();
  // 创建相机
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
  // 设定相机位置和观察位置
  camera.position.z = 250;
  camera.position.y = 400;
  camera.lookAt(0, 0, 0)
  // scene.background = null; // 背景透明
  scene.background = new THREE.Color(0x1e232e)
  // 创建渲染器
  renderer = new THREE.WebGLRenderer({
    antialias: true, // 抗锯齿
    // alpha: true,
  });
}
initScene()

// 引入挂载DOM的ref
const container = ref()
const gltfLoader = new GLTFLoader();



function initLight() {
  // 加入环境光
  const ambientlight = new THREE.AmbientLight(0x404040); // 柔和的白光
  scene.add(ambientlight);
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  // directionalLight.position = THREE.Object3D.DEFAULT_UP

  scene.add(directionalLight);
}

// 地板元素
let baseFloor;
function initBaseFloor() {
  const geometry = new THREE.PlaneGeometry(4800, 2400);
  const material = new THREE.MeshBasicMaterial({
    color: 0x333333,
    transparent: true, // 开启透明
    opacity: 0 // 透明度为0 
  });
  baseFloor = new THREE.Mesh(geometry, material);
  baseFloor.rotateX(-Math.PI / 2)
  baseFloor.visible = false
  scene.add(baseFloor);
}

// 加载储存的对象
const objectLoader = new THREE.ObjectLoader();


const cadGroup = new THREE.Group();
cadGroup.name = 'CAD图纸'
let offset: any[] = []
// 画图层
function drawLayers({ centerPoints, layers }: any) {
  // 偏移量
  offset = [centerPoints[0], centerPoints[1]]
  // 缩放比例
  const scale = 0.1
  layers.forEach((layer: any) => {
    const group = new THREE.Group();
    group.name = layer.layer
    drawLines(group, layer.lines, offset, scale)
    cadGroup.add(group)
  })
  cadGroup.rotation.x = -Math.PI / 2 // 图纸旋转90度
  cadGroup.position.y = 0.5 // 位置提高一点，方便浏览

  scene.add(cadGroup)
  // console.log(scene)
}

function drawLines(group: any, lines: any, offset: any, scale: any) {
  lines.forEach((item: any) => {
    const lineMaterial = new LineMaterial({
      color: 0x7c7c7c, // 线条颜色
      linewidth: 4, // 线条宽度
      dashed: false, // 是否是虚线
    });
    //材质的分辨率必须设置，要不显示的线宽度不正确 
    lineMaterial.resolution.set(window.innerWidth, window.innerHeight);
    const material = new THREE.LineBasicMaterial();
    const points = item.vertices.map((point: any) => {
      return new THREE.Vector3(point.x - offset[0], point.y - offset[1], 0)
    });
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    geometry.scale(scale, scale, scale)
    const lineSegments = new THREE.LineSegments(geometry, material);
    const lineGeometry = new LineGeometry();
    lineGeometry.fromLineSegments(lineSegments);
    const line2 = new Line2(lineGeometry, lineMaterial);
    group.add(line2);
  })
}


function drawLayers2({ centerPoints, layers }: any) {
  // 偏移量
  offset = [centerPoints[0], centerPoints[1]]
  // 缩放比例
  const scale = 0.1
  layers.forEach((layer: any) => {
    const group = new THREE.Group();
    group.name = layer.layer
    drawLines2(group, layer.lines, offset, scale)
    cadGroup.add(group)
  })
  cadGroup.rotation.x = -Math.PI / 2 // 图纸旋转90度
  cadGroup.position.y = 0.5 // 位置提高一点，方便浏览

  scene.add(cadGroup)
  // console.log(scene)
}
const localPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), -0.5);

function drawLines2(group: any, lines: any, offset: any, scale: any) {
  // 地面材质
  const material2 = new THREE.LineBasicMaterial({
    transparent: true, // 开启透明
    color: 0xB2E0CB,
    opacity: 0.0
  });
  // 管道材质
  const material = new THREE.MeshPhongMaterial({
    color: 0xB2E0CB,
    side: THREE.DoubleSide,
    transparent: true, // 开启透明
    opacity: 0.3, // 透明度为0
    clippingPlanes: [localPlane],
  });
  material.shininess = 100
  lines.forEach((item: any) => {
    if (item.vertices.length > 1) {
      const points = item.vertices.map((point: any) => {
        return new THREE.Vector3(point.x - offset[0], point.y - offset[1], 0)
      });
      const curve = new THREE.CatmullRomCurve3(points);
      curve.curveType = "catmullrom";
      curve.closed = false;//设置是否闭环
      curve.tension = 0; //设置线的张力，0为无弧度折线
      const geometry = new THREE.TubeGeometry(curve, 20, 20, 8, false);

      geometry.scale(scale, scale, scale)
      const tube = new THREE.Mesh(geometry, material);
      group.add(tube);

      const pointsMap = item.vertices.map((item: any) => {
        return {
          x: item.x - offset[0],
          y: item.y - offset[1]
        }
      })
      const points2 = createShapeFromPoints(pointsMap, 20);
      const shape2 = new THREE.Shape(points2);
      const geometry2 = new THREE.ShapeGeometry(shape2);
      geometry2.scale(scale, scale, scale)
      const line2 = new THREE.Mesh(geometry2, material2);
      group.add(line2);
    }
  })
}

/**
 * 线拉伸成平面
 * @param { {x: number, y: number}[] } points 点
 * @param { number } radius 拉伸半径(宽度)
 * @returns { THREE.Vector2[] }
 */
function createShapeFromPoints(points: { x: number, y: number }[], radius: number = 1): THREE.Vector2[] {
  let left = [];
  let right = [];

  for (let i = 0, len = points.length; i < len; i++) {
    let prev = points[i - 1] || {};
    let curr = points[i];
    let next = points[i + 1] || {};

    let v1: any = [curr.x - prev.x, curr.y - prev.y];
    let v2: any = [next.x - curr.x, next.y - curr.y];
    if (!prev.x && prev.x !== 0) {
      v1 = [...v2];
    } else if (!next.x && next.x !== 0) {
      v2 = [...v1];
    }

    let modelV1 = Math.sqrt(v1[0] ** 2 + v1[1] ** 2);
    let modelV2 = Math.sqrt(v2[0] ** 2 + v2[1] ** 2);
    // 单位向量
    v1 = [v1[0] / modelV1, v1[1] / modelV1];
    v2 = [v2[0] / modelV2, v2[1] / modelV2];
    // 方向和的单位向量
    let vector: any = [v1[0] + v2[0], v1[1] + v2[1]];
    let modelVector = Math.sqrt(vector[0] ** 2 + vector[1] ** 2);
    vector = [vector[0] / modelVector, vector[1] / modelVector];

    // 扩散点的方向和转角处的角度偏移
    let Lvector = rotateVector(vector, -Math.PI / 2);
    let Rvector = rotateVector(vector, Math.PI / 2);
    let deflection = vectorAngleCosHalf(v1, v2);

    left.push(
      new THREE.Vector2(
        curr.x + Lvector[0] * (radius / deflection),
        curr.y + Lvector[1] * (radius / deflection)
      )
    );
    right.unshift(
      new THREE.Vector2(
        curr.x + Rvector[0] * (radius / deflection),
        curr.y + Rvector[1] * (radius / deflection)
      )
    );

    prev = curr;
  }

  return left.concat(right);
}

/**
 * 向量夹角的cos值
 * @param { [number, number] } a
 * @param { [number, number] } b
 * @returns
 */
function vectorAngleCos(a: [number, number], b: [number, number]) {
  return (
    (a[0] * b[0] + a[1] * b[1]) /
    (Math.sqrt(a[0] ** 2 + a[1] ** 2) * Math.sqrt(b[0] ** 2 + b[1] ** 2))
  );
}

/**
 * 向量夹角的一半的cos值
 * @param { [number, number] } a
 * @param { [number, number] } b
 * @returns
 */
function vectorAngleCosHalf(a: [number, number], b: [number, number]) {
  return Math.sqrt((1 + vectorAngleCos(a, b)) / 2);
}

/**
 * 将点绕原点旋转
 * @param { [number, number] } param0
 * @param { number } angle
 * @returns { [number, number] }
 */
function rotateVector([x1, y1]: [number, number], angle: number): [number, number] {
  let x2 = x1 * Math.cos(angle) - y1 * Math.sin(angle);
  let y2 = y1 * Math.cos(angle) + x1 * Math.sin(angle);

  return [x2, y2];
}

const floorGroup = new THREE.Group();
floorGroup.name = 'floor'
let floorStone = null
// // 纹理加载器
const textureLoader = new THREE.TextureLoader();
function initStoneFloor(data: any) {
  const floorData = data.points
  const centerPoints = data.centerPoints
  const shape = new THREE.Shape();
  floorData.forEach((item: any, index: any) => {
    if (index === 1) {
      shape.moveTo(item[0] - centerPoints[0], item[1] - centerPoints[1]);
    } else {
      shape.lineTo(item[0] - centerPoints[0], item[1] - centerPoints[1])
    }
  })
  shape.lineTo(floorData[0][0] - centerPoints[0], floorData[0][1] - centerPoints[1]) // 闭合路径

  // 创建形状的几何体
  const geometry = new THREE.ShapeGeometry(shape);

  const texture = textureLoader.load(Stone);
  texture.colorSpace = THREE.SRGBColorSpace
  texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
  texture.repeat.set(0.00009, 0.00009);
  texture.offset.set(0.5, 0.5)
  // 创建材质
  const material = new THREE.MeshBasicMaterial({
    color: 0x34455a
  });
  geometry.scale(0.10, 0.10, 0.10)

  floorStone = new THREE.Mesh(geometry, material);
  floorStone.position.z = 0
  floorGroup.add(floorStone)


  const wall = creatWallByPath(floorData, centerPoints)
  wall.scale.set(0.10, 0.10, 0.10)
  floorGroup.add(wall)

  floorGroup.rotation.x = -Math.PI / 2 // 图纸旋转90度
  // floorGroup.position.y = 0.5 // 位置提高一点，方便浏览
  scene.add(floorGroup)
}


function creatWallByPath(data: any, offset: any) {
  // 1.1向y方向拉伸顶点
  const verticesByTwo = data.reduce((arr: any, [x, y]: [number, number]) => {
    return arr.concat([
      [
        [x - offset[0], y - offset[1], 0],
        [x - offset[0], y - offset[1], -200],
      ],
    ]);
  }, []);
  // 2.解析需要渲染的四边形 每4个顶点为一组
  const verticesByFour = verticesByTwo.reduce((arr: any, item: any, i: any) => {
    if (i === verticesByTwo.length - 1) return arr;
    return arr.concat([[item, verticesByTwo[i + 1]]]);
  }, []);

  // 3.将四边形面转换为需要渲染的三顶点面
  const verticesByThree = verticesByFour.reduce((arr: any, item: any) => {
    const [[point1, point2], [point3, point4]] = item;
    return arr.concat(
      ...point2,
      ...point1,
      ...point4,
      ...point1,
      ...point3,
      ...point4
    );
  }, []);

  const geometry = new THREE.BufferGeometry();
  // 4. 设置position
  const vertices = new Float32Array(verticesByThree);
  geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
  // 5. 设置uv 6个点为一个周期 [0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1]

  // 5.1 以18个顶点为单位分组
  const pointsGroupBy18 = new Array(verticesByThree.length / 3 / 6)
    .fill(0)
    .map((item, i) => {
      return verticesByThree.slice(i * 3 * 6, (i + 1) * 3 * 6);
    });
  // 5.2 按uv周期分组
  const pointsGroupBy63 = pointsGroupBy18.map((item, i) => {
    return new Array(item.length / 3)
      .fill(0)
      .map((it, i) => item.slice(i * 3, (i + 1) * 3));
  });
  // 5.3根据BoundingBox确定uv平铺范围
  geometry.computeBoundingBox();
  const { min, max } = geometry.boundingBox as any;
  const rangeX = max.x - min.x;
  const uvs = [].concat(...pointsGroupBy63.map((item) => {
    const point0 = item[0];
    const point5 = item[5];
    const distance = new THREE.Vector3(...point0).distanceTo(new THREE.Vector3(...point5)) / (rangeX / 10);
    return [0, 1, 0, 0, distance, 1, 0, 0, distance, 0, distance, 1];
  }) as any
  );
  geometry.setAttribute(
    "uv",
    new THREE.BufferAttribute(new Float32Array(uvs), 2)
  );
  // 更新法线
  // geometry.computeVertexNormals();

  // 顶点着色器
  const vertexShader = `
  uniform vec3 u_color;

  uniform float time;
  uniform float u_height;
  varying float v_opacity;
  
  void main() {
    vec3 vPosition = position;
    v_opacity = mix(1.0, 0.0, -position.z / u_height * 1.0) * (1.0 + sin(time) * 0.5);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1);
}
`

  // 片元着色器
  const fragmentShader = `
          uniform vec3 u_color;
          uniform float u_opacity;
          varying float v_opacity;
          void main() {
              gl_FragColor = vec4(u_color, v_opacity * u_opacity);
          }`

  const meshMat = new THREE.ShaderMaterial({
    uniforms: {
      u_height: {
        value: 200,
      },
      u_opacity: {
        value: 0.8,
      },
      u_color: {
        value: new THREE.Color(0xc9d3da),
      },
    },
    transparent: true,
    depthWrite: false,
    side: THREE.DoubleSide,
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
  });

  return new THREE.Mesh(geometry, meshMat);

}


// 获取巷道数据
function getAllLineModel(data: any[]) {
  const group = new THREE.Group();
  group.name = '巷道'
  data.forEach(element => {
    createTunnel(group, element)
  });
  scene.add(group)
}
/**
 * 建立巷道
 * @param group 
 * @param data 
 */
function createTunnel(group: THREE.Group, data: any) {
  const raidus = data.width // 半径
  const tubeColor = data.color ? new THREE.Color(data.color) : new THREE.Color('#e6e6e6')

  const material = new THREE.MeshPhongMaterial({
    color: tubeColor,
    shininess: 100
  });
  const points = [new THREE.Vector3(mapInfo.cadToWeb3dX(data.startX), 0, mapInfo.cadToWeb3dY(data.startY)), new THREE.Vector3(mapInfo.cadToWeb3dX(data.endX), 0, mapInfo.cadToWeb3dY(data.endY))]
  // 创建封口两个球面
  const sphereGeo = new THREE.SphereGeometry(raidus, 32, 16);
  const sphere1 = new THREE.Mesh(sphereGeo, material);
  const sphere2 = sphere1.clone();
  sphere1.position.set(points[0].x, points[0].y, points[0].z);
  sphere2.position.set(points[1].x, points[1].y, points[1].z)
  group.add(sphere1);
  group.add(sphere2);
  // 创建曲线
  const curve = new THREE.CatmullRomCurve3(points);
  curve.curveType = "catmullrom";
  curve.closed = false;//设置是否闭环
  curve.tension = 0; //设置线的张力，0为无弧度折线
  const geometry = new THREE.TubeGeometry(curve, 2, raidus, 16, false);
  const tube = new THREE.Mesh(geometry, material);
  tube.userData = data
  group.add(tube);
}

let worker: any = null

function initPeople(x: number, y: number) {
  if (worker) {
    // worker.lookAt(x, 10, y)
    gsap.to(worker.position, { x, z: y, duration: 2 })
  } else {
    const texture = textureLoader.load(Worker)
    texture.colorSpace = THREE.SRGBColorSpace
    const material = new THREE.SpriteMaterial({ map: texture });
    worker = new THREE.Sprite(material)
    worker.scale.set(10, 16, 1)
    worker.position.set(mapInfo.cadToWeb3dX(x), 12, mapInfo.cadToWeb3dY(y))
    scene.add(worker)
    // gltfLoader.load(Worker, function (gltf) {
    //   // 转动z轴与朝向相同
    //   worker = gltf.scene;
    //   worker.children[0].rotateY(Math.PI)
    //   worker.scale.set(10, 10, 10)
    //   worker.position.set(x, 10, y)
    //   scene.add(worker)
    // })
  }
}

// 看向人物
function lookAtPeople() {
  camera.position.x = worker.position.x
  camera.position.z = worker.position.z + 100
  camera.position.y = 150
  camera.lookAt(worker.position)
  controls.target.x = worker.position.x
  controls.target.y = worker.position.y
  controls.target.z = worker.position.z
}

function lookAtPoint(pointData: PointInfoParam) {
  camera.position.set(pointData.posX, pointData.posZ, pointData.posY)
  camera.position.z += 100
  camera.position.y += 150
  camera.lookAt(transformVector3(pointData.posX, pointData.posZ, pointData.posY))
  controls.target.x = mapInfo.cadToWeb3dX(pointData.posX)
  controls.target.y = pointData.posZ
  controls.target.z = mapInfo.cadToWeb3dY(pointData.posY)
}
// 新建标签
function createLableObj(text: string) {
  let laberDiv = document.createElement('div');//创建div容器
  laberDiv.className = 'laber-name';
  laberDiv.textContent = text;
  laberDiv.style.backgroundColor = 'transparent';
  laberDiv.style.color = '#409eff'


  let pointLabel = new CSS2DObject(laberDiv);
  pointLabel.position.set(0, 2, 0);
  pointLabel.center.set(0.5, 1);
  // pointLabel.layers.set(0);
  return pointLabel;
}

function createPointDetailObj(data: any) {
  let laberDiv = document.createElement('div');//创建div容器
  laberDiv.className = 'p-detail';

  const html = `<div style="padding: 20px; background-color: #000000; color: #fff;border: 3px solid #409EFF;border-radius: 5px;">
                    <ul>
                        <li>名称：${data.name}</li>
                        <li>类型：${data.typeName}</li>
                    </ul>
                </div>`
  laberDiv.innerHTML = html
  let pointLabel = new CSS2DObject(laberDiv);
  pointLabel.position.set(0, 20, 0);
  pointLabel.center.set(0.5, 1);
  pointLabel.layers.set(0);
  return pointLabel;
}
// 批量创建询价点
function dataToPoints(val: string | PointInfoParam[]) {
  if (val === '') return
  if (typeof val === 'string') {
    val = JSON.parse(val) as PointInfoParam[]
  }
  createCheckPoints(val)
}

let pointList: THREE.Object3D[] = []
scene.add(pointList)
function createCheckPoints(rows: PointInfoParam[]) {
  rows.forEach((item, index) => {
    pointList[index] = createPointModel(item)
    scene.add(pointList[index])
  })
  nearValue = controls.getDistance()
  mergePointData(pointList)
}

// 屏幕点模型
function createPointModel(item: PointInfoParam): THREE.Object3D {
  const vertices = [0, 0, 0]
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
  const material = new THREE.PointsMaterial({
    transparent: true,
    opacity: 0 // 透明度为0
  });
  const point = new THREE.Points(geometry, material);
  point.name = 'point'
  point.userData = item
  point.position.set(mapInfo.cadToWeb3dX(item.posX), 0, mapInfo.cadToWeb3dY(item.posY))
  let css2Model
  css2Model = create2DPointModel(item)
  css2Model.name = 'pointModel'
  point.add(css2Model)
  return point
}

function create2DPointModel(item: PointInfoParam) {
  const pointPics = [PointPic1, PointPic2, PointPic3, PointPic4]

  let laberDiv = document.createElement('div') as HTMLElement;//创建div容器
  laberDiv.className = 'p-model';
  const html = `<div style="background: url(${pointPics[item.inspecStatus]}) no-repeat; background-size: 100% 100%; width: 80px; height: 50px;padding: 8px 2px;box-sizing: border-box;overflow: hidden;white-space: nowrap;text-overflow:ellipsis; text-align: center;font-size: 12px; color: #fff; transform: scale(0.7);">
        ${item.name}
    </div>`
  laberDiv.innerHTML = html
  let pointLabel = new CSS2DObject(laberDiv);
  pointLabel.position.set(0, 0, 0); // 在父元素的相对位置
  pointLabel.center.set(0.5, 1); // DOM元素中心点位置（1，1）=（100%，100%）
  return pointLabel;
}
// 灾害标志
function dataToPointsForZh(val: string | PointInfoParam[]) {
  if (val === '') return
  if (typeof val === 'string') {
    val = JSON.parse(val) as PointInfoParam[]
  }
  createCheckPointsForZh(val)
}
function createCheckPointsForZh(rows: PointInfoParam[]) {
  rows.forEach((item, index) => {
    pointList[index] = createPointModelForZh(item)
    scene.add(pointList[index])
  })
  nearValue = controls.getDistance()
  mergePointData(pointList)
}

// 屏幕点模型
function createPointModelForZh(item: PointInfoParam): THREE.Object3D {
  const vertices = [0, 0, 0]
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
  const material = new THREE.PointsMaterial({
    transparent: true,
    opacity: 0 // 透明度为0
  });
  const point = new THREE.Points(geometry, material);
  point.name = 'point'
  point.userData = item
  point.position.set(item.posX, 0, item.posY)
  let css2Model
  css2Model = create2DPointModelForZh(item)
  css2Model.name = 'pointModel'
  point.add(css2Model)
  return point
}

// 八大灾害图标
const zhBd = [ZhDb0, ZhDb1, ZhDb2, ZhDb3]
const zhFc = [ZhFc0, ZhFc1, ZhFc2, ZhFc3]
const zhFmh = [ZhFmh0, ZhFmh1, ZhFmh2, ZhFmh3]
const zhKy = [ZhKy0, ZhKy1, ZhKy2, ZhKy3]
const zhSh = [ZhSh0, ZhSh1, ZhSh2, ZhSh3]
const zhWs = [ZhWs0, ZhWs1, ZhWs2, ZhWs3]
const zhZx = [ZhZx0, ZhZx1, ZhZx2, ZhZx3]
const zhTf = [ZhTf0, ZhTf1, ZhTf2, ZhTf3]

function create2DPointModelForZh(item: PointInfoParam): THREE.Object3D {
  let object
  switch (item.inspecType) {
    case 'tf':
      object = zhTf
      break;
    case 'fc':
      object = zhFc
      break;
    case 'ws':
      object = zhWs
      break;
    case 'fmh':
      object = zhFmh
      break;
    case 'sh':
      object = zhSh
      break;
    case 'db':
      object = zhBd
      break;
    case 'ky':
      object = zhKy
      break;
    case 'zx':
      object = zhZx
      break;
    default:
      object = zhZx
      break;
  }
  const laberDiv = document.createElement('div');//创建div容器
  laberDiv.className = 'p-model';
  const html = `<div style="background: url(${object[item.inspecStatus]}) no-repeat; background-size: 100% 100%; width: 25px; height: 30px; position: relative;">
    <div style="position: absolute; top:-20px; left:50%; transform: translateX(-50%); color: #fff;font-weight: 600;width: max-content;">${item.name}</div></div>`
  laberDiv.innerHTML = html
  laberDiv.style.zIndex = '999'
  const pointLabel = new CSS2DObject(laberDiv);
  pointLabel.position.set(0, 0, 0); // 在父元素的相对位置
  pointLabel.center.set(0.5, 1); // DOM元素中心点位置（1，1）=（100%，100%）
  return pointLabel;
}

// 在场景中移除所有点
function removeAllPoint() {
  pointList.forEach(item => {
    item.remove(item.children[0]) // 移除CSS标签
  })
  scene.remove(...pointList)
  pointList = []
}

// 巡检路线
// let line2: Line2 | null

let lineList: Line2[]

function initLine(inspectionPath: any) {
  // if (line2) {
  //   scene.remove(line2)
  //   line2 = null
  // }

  const v3Arr: any[] = []
  if (inspectionPath !== '') {
    const path = JSON.parse(inspectionPath)
    path.forEach((point: any) => {
      // y 轴抬高一点好辨识
      v3Arr.push(mapInfo.cadToWeb3dX(point.x), point.y + 1.0, mapInfo.cadToWeb3dY(point.z))
    })
  }
  const lineMaterial = new LineMaterial({
    color: 0xff0000, // 线条颜色
    linewidth: 5, // 线条宽度
    dashed: false, // 是否是虚线
  });
  //材质的分辨率必须设置，要不显示的线宽度不正确 
  lineMaterial.resolution.set(window.innerWidth, window.innerHeight);
  const lineGeometry = new LineGeometry();
  lineGeometry.setPositions(new Float32Array(v3Arr));
  // 创建 Line2 对象
  const line2 = new Line2(lineGeometry, lineMaterial);
  scene.add(line2)
  lineList.push(line2)
}
function removeAllLine2() {
  lineList.forEach(item => {
    scene.remove(item)
  })
  lineList = []
}

// 显示详情
function showDetail(object: any) {
  object.traverse((item: any) => {
    if (item.name === 'detailDom') {
      item.visible = true
    }
  })
}
// 隐藏所有的标签
function hiddenAllDetail() {
  scene.traverse((item: any) => {
    if (item.name === 'detailDom') {
      item.visible = false
    }
  })
}

let mineFaceGroup = new THREE.Group();
mineFaceGroup.name = 'mineFace'
mineFaceGroup.rotation.x = Math.PI / 2 // 图纸旋转90度
mineFaceGroup.position.y = 1
scene.add(mineFaceGroup)
function createMineFace(data: any) {
  data.points = JSON.parse(data.points)
  data.points.forEach((item: any) => {
    item.x = mapInfo.cadToWeb3dX(item.x)
    item.z = mapInfo.cadToWeb3dY(item.z)
  })
  const shape = new THREE.Shape();
  let maxX: number = 0, minX: number = 0, maxZ: number = 0, minZ: number = 0
  data.points.forEach((item: any, index: number) => {
    if (index === 1) {
      maxX = item.x
      minX = item.x
      maxZ = item.z
      minZ = item.z
      shape.moveTo(item.x, item.z);
    } else {
      shape.lineTo(item.x, item.z)
      if (maxX < item.x) {
        maxX = item.x
      }
      if (minX > item.x) {
        minX = item.x
      }
      if (maxZ < item.z) {
        maxZ = item.z
      }
      if (minZ > item.z) {
        minZ = item.z
      }
    }
  })
  //计算中心点
  const center = [maxX - (maxX - minX) / 2, maxZ - (maxZ - minZ) / 2] as [number, number]

  shape.lineTo(data.points[0].x, data.points[0].z) // 闭合路径

  // 创建形状的几何体
  const geometry = new THREE.ShapeGeometry(shape);
  const material = new THREE.MeshBasicMaterial({
    color: 0x00ffff,
    transparent: true,
    opacity: 0.6, // 透明度为0
    side: THREE.DoubleSide
  });
  const mesh = new THREE.Mesh(geometry, material);
  const css2Obj = createAreaLableObj(data.name, center)
  mesh.name = 'faceObj'
  mesh.add(css2Obj)
  mineFaceGroup.add(mesh)
}


// 新建标签
function createAreaLableObj(text: string, center: [number, number]) {
  let laberDiv = document.createElement('div');//创建div容器
  // laberDiv.textContent = text;
  // laberDiv.style.color = '#409eff'
  const html = `
        <div>${text}</div>`
  laberDiv.innerHTML = html

  let label = new CSS2DObject(laberDiv);
  label.position.set(center[0], center[1], 0);
  label.center.set(0.5, 0.5);
  return label;
}


const raycaster = new THREE.Raycaster();
// 获取投射目标
function getIntersects(clientX: number, clientY: number) {
  if (container.value.offsetWidth) {
    const mouse = new THREE.Vector2(
      (clientX / container.value.offsetWidth) * 2 - 1,
      -(clientY / container.value.offsetHeight) * 2 + 1
    );
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObject(scene, true);
    return intersects
  } else {
    return []
  }

}
// 鼠标单击场景
function handleClickScene(event: MouseEvent) {

}
// 处理点击底部添加点
function handllerdblclickScene(event: MouseEvent) {

}
// 创建GUI对象
// const gui: dat.GUI = new dat.GUI();
// 添加操作界面
// function initGui() {
//   const guiOptions = {
//     test() {
//       console.log(pointList);

//     }
//   }
//   gui.add(guiOptions, 'test')
//     .name('测试')

// }

/**
 * CAD转换世界坐标
 * @param {number} x 
 * @param {number} y 
 * @param {number} z 
 * @returns {THREE.Vector3}
 */
function transformVector3(x: number, y: number, z: number) {
  return new THREE.Vector3(mapInfo.cadToWeb3dX(x), y, mapInfo.cadToWeb3dY(z))
}


onUnmounted(() => {
  // gui.destroy()
})

function init() {
  // initBaseFloor()
  // initStoneFloor(Edge)
  // drawLayers2(Cad)
  initLight()
  // initGui()

}
init()
// 鼠标经过处理
function handleMousemoveScene(event: MouseEvent) {
  const intersects = getIntersects(event.clientX, event.clientY)
  if (intersects.length <= 0) return void 0;
  const object = intersects[0].object
  if (object.name === 'huitugou_2152_83' || object.name === 'point') {
    if (object.visible === true) {
      showDetail(object)
    }
  } else {
    hiddenAllDetail()
  }
}
let labelRenderer: any
// 创建轨道控制器
// const controls = new OrbitControls(camera, renderer.domElement);
// 建立时钟对象
const clock = new THREE.Clock();//计时器
const FPS = 60; // 指的是 60帧每秒的情况
const singleFrameTime = (1 / FPS);
let timeStamp = 0;
// 动画函数
function animate() {
  requestAnimationFrame(animate);

  const delta = clock.getDelta(); //获取距离上次请求渲染的时间

  timeStamp += delta;

  if (timeStamp > singleFrameTime) {
    render();//渲染
    // 剩余的时间合并进入下次的判断计算 这里使用取余数是因为 当页页面失去焦点又重新获得焦点的时候，delta数值会非常大， 这个时候就需要
    timeStamp = (timeStamp % singleFrameTime);
  }
}


function render() {
  if (controls.target.x < -600 || controls.target.x > 600 || controls.target.z < -200 || controls.target.z > 400) {
    controls.reset()
  } else {
    controls.saveState();
  }
  // controls.update()

  renderer.render(scene, camera);

  labelRenderer.render(scene, camera);
}
// 改变屏幕尺寸调整3D比例
function resizeView() {
  // 更新摄像头
  camera.aspect = container.value.clientWidth / container.value.clientHeight
  // 更新投影几的投影矩阵
  camera.updateProjectionMatrix()
  // 更新渲染器尺寸
  renderer.setSize(container.value.clientWidth, container.value.clientHeight)
  // 设置当前设备的像素比,pc和移动端区别
  renderer.setPixelRatio(window.devicePixelRatio)

  labelRenderer.setSize(container.value.clientWidth, container.value.clientHeight);
}
let nearValue = 100 // 判断靠近阀值
// 聚合数据函数
function mergePointData(data: THREE.Object3D[]) {
  data.forEach(item => {
    item.children[0].visible = true
  })
  data.forEach((item, index) => {
    if (index === 0 || item.children[0].visible) {
      // console.log(item.showPoint);
      data.forEach((item2, index2) => {
        if (index2 > 0 && item.id !== item2.id && item2.children[0].visible) {
          if (hasNearPoint(item, item2)) {
            item2.children[0].visible = false
          }
        }
      })
    }
  })
  // console.log('聚合', data);
}
// 判断靠近点
function hasNearPoint(item: THREE.Object3D, item2: THREE.Object3D) {
  return item.position.distanceTo(item2.position) < (nearValue / 10)
}
let controls: MapControls
// 挂载生命周期
onMounted(() => {
  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(container.value.clientWidth, container.value.clientHeight);
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = '0px';
  container.value.appendChild(labelRenderer.domElement);
  controls = new MapControls(camera, labelRenderer.domElement);
  // 垂直旋转的角度的上限
  controls.maxPolarAngle = Math.PI / 6
  controls.minPolarAngle = Math.PI / 6
  // 水平旋转的角度的上限
  controls.minAzimuthAngle = 0
  controls.maxAzimuthAngle = 0
  // // 垂直旋转的角度的上限
  controls.maxDistance = 2000
  controls.minDistance = 10

  container.value.appendChild(renderer.domElement)

  window.addEventListener('resize', resizeView)

  resizeView()

  animate()
  // 鼠标双击事件
  // container.value.addEventListener('dblclick', handllerdblclickScene)
  // 鼠标单击事件
  // container.value.addEventListener('click', handleClickScene)

  // container.value.addEventListener('mousemove', handleMousemoveScene)

  // 控制器改变事件
  controls.addEventListener('change', function (event) {
    nearValue = controls.getDistance()
    mergePointData(pointList)

  })

  // 巡检点
  window.$initAllpoints = dataToPoints
  // 巡检路线
  window.$initLine = initLine

  window.$removeAllLine = removeAllLine2
  // 人物定位
  window.$initPeople = initPeople
  // 看向人物
  window.$lookAtPeople = lookAtPeople
  // 完成度路线
  window.$drawCompleteLine = drawCompleteLine
  // 删除完成度路线
  window.$removeCompleteLines = removeCompleteLines
  // 删除地图山的点
  window.$removeAllPoint = removeAllPoint
  // 逃生路线
  window.$createEscapeLine = createEscapeLine
  // 移除逃生路线
  window.$removeAllEscapeLine = removeAllEscapeLine
  // 添加工作面
  window.$initMineFace = createMineFace
  // 灾害点
  window.$initZhPoints = dataToPointsForZh
  // 看向点位
  window.$lookAtPoint = lookAtPoint
  // 建立巷道模型
  window.$createAllLineModel = getAllLineModel
})
onUnmounted(() => {
})


let completeLines: Line2[] = []
// 画完成度线路
function drawCompleteLine(positionList: { x: number, y: number, z: number }[]) {
  const lineMaterial = new LineMaterial({
    color: 0x3ab904, // 线条颜色
    linewidth: 5, // 线条宽度
    dashed: false, // 是否是虚线
  });
  lineMaterial.resolution.set(window.innerWidth, window.innerHeight);

  positionList.forEach((item: any) => item.y = 1.0)
  const material = new THREE.LineBasicMaterial();
  const points = positionList.map((item: any) => transformVector3(item.x, item.y, item.z))
  const geometry = new THREE.BufferGeometry().setFromPoints(points);
  const line = new THREE.LineSegments(geometry, material);
  const lineGeometry = new LineGeometry();
  lineGeometry.fromLineSegments(line);
  const line2 = new Line2(lineGeometry, lineMaterial);
  completeLines.push(line2)
  scene.add(line2)
}
// 移除完成度线路
function removeCompleteLines() {
  scene.remove(...completeLines)
  completeLines = []
}


let escapeLineGroup = new THREE.Group()
scene.add(escapeLineGroup)
function createEscapeLine(inspectionPath: string) {
  let curve
  if (inspectionPath !== '') {
    const path = JSON.parse(inspectionPath)
    const points = path.map((item: any) => transformVector3(item.x, item.y, item.z))
    curve = new THREE.CatmullRomCurve3(points);
    curve.curveType = "catmullrom";
    curve.closed = false;//设置是否闭环
    curve.tension = 0; //设置线的张力，0为无弧度折线
  }
  // 绘制巡检路线带流动动画效果
  const checkLineTexture = textureLoader.load(CheckLineTexture);
  checkLineTexture.colorSpace = THREE.SRGBColorSpace
  checkLineTexture.wrapS = THREE.RepeatWrapping;
  checkLineTexture.repeat.set(20, 1);
  gsap.to(checkLineTexture.offset, {
    x: -1,
    duration: 1,
    repeat: -1,
    ease: "none",
  });
  const geometry = new THREE.TubeGeometry(curve, 20, 2, 8, false);
  const material = new THREE.MeshBasicMaterial({
    // color: 0x00ff00, 
    map: checkLineTexture,
    side: THREE.DoubleSide,
  });
  const mesh = new THREE.Mesh(geometry, material);
  escapeLineGroup.add(mesh)
}
function removeAllEscapeLine() {
  scene.remove(escapeLineGroup)
  escapeLineGroup = new THREE.Group()
  scene.add(escapeLineGroup)
}
</script>

<template>
  <div id="scene-page">
    <div class="main-view" ref="container"></div>
  </div>
</template>
<style lang="scss" scoped>
#scene-page {
  position: relative;
  height: 100vh;

  .main-view {
    height: 100%;
  }

  .fixed-left {
    position: absolute;
    top: 0px;
    left: 0px;
    overflow: auto;
    display: flex;
    flex-direction: column;
  }

  .fixed-right {
    position: absolute;
    top: 0px;
    right: 0px;
    overflow: auto;
    display: flex;
    flex-direction: column;
  }
}

// gui 样式
:deep(#gui) {
  position: absolute;
  top: 0;
  right: 0;
}
</style>